#include "LecteurPhraseAvecArbre.h"

#include <stdlib.h>
#include <iostream>
using namespace std;

////////////////////////////////////////////////////////////////////////////////
LecteurPhraseAvecArbre::LecteurPhraseAvecArbre(string nomFich) : ls(nomFich), ts() {
}
////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecArbre::analyse() {
	arbre=programme();
	cout << "Syntaxe correcte." << endl;
}
////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecArbre::testerSymCour(string ch) {
	if (ls.getSymCour() != ch) {
		cout << endl << "-------- Erreur ligne " << ls.getLigne()
				<< " - Colonne " << ls.getColonne() << endl << "   Attendu : "
				<< ch << endl << "   Trouve  : " << ls.getSymCour() << endl
				<< endl;
		exit(0); // plus tard, on levera une exception
	}
}
////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecArbre::sauterSymCour(string ch) {
	testerSymCour(ch);
	ls.suivant();
}
////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecArbre::erreur(string mess) {
	cout << endl << "-------- Erreur ligne " << ls.getLigne() << " - Colonne "
			<< ls.getColonne() << endl << "   Attendu : " << mess << endl
			<< "   Trouve  : " << ls.getSymCour() << endl << endl;
	exit(0); // plus tard, on levera une exception
}

////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::opAdd() {
// <opAdd> ::= + | -
    Symbole operateur;
    if ((ls.getSymCour()=="+") || (ls.getSymCour()=="-"))
    {
        operateur=ls.getSymCour();
        ls.suivant();
    }
    else
        erreur("<opAdd>");
    return operateur;
}
////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::opEt() {
// <opEt> ::= et
    Symbole operateur;
    if (ls.getSymCour()=="et")
    {
        operateur=ls.getSymCour();
        ls.suivant();
    }        
    else
        erreur("<opEt>");
    return operateur;
}
////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::opMult() {
// <opMult> ::= * | /
    Symbole operateur;
    if ((ls.getSymCour()=="*") || (ls.getSymCour()=="/"))
    {
        operateur=ls.getSymCour();
        ls.suivant();
    }
    else
        erreur("<opMult>");
    return operateur;
}
////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::opOu() {
// <opOu> ::= ou
    Symbole operateur;
    if (ls.getSymCour()=="ou")
    {
        operateur=ls.getSymCour();
        ls.suivant();
    }

    else
        erreur("<opOu>");
    return operateur;
}
////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::opRel() {
// <opRel> ::= == | != | < | <= | > | >=
    Symbole operateur;
    if ((ls.getSymCour()=="==" || ls.getSymCour()=="!=" || ls.getSymCour()=="<" || ls.getSymCour()=="<=" || ls.getSymCour()==">" || ls.getSymCour()==">="))
    {
        operateur=ls.getSymCour();
        ls.suivant();
    }
    else
        erreur("<opRel>");
    return operateur;
}
////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::opUnaire() {
// <opUnaire> ::= - | non
    Symbole operateur;
    if (ls.getSymCour()=="-" || ls.getSymCour()=="non")
    {
        operateur=ls.getSymCour();
        ls.suivant();
    }
    else
        erreur("<opUnitaire>");
    return operateur;
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::affectation() {
// <affectation> ::= <variable> = <expBool>
    	testerSymCour("<VARIABLE>");
	Noeud* var = ts.chercheAjoute(ls.getSymCour());
	ls.suivant();
	sauterSymCour("=");
	Noeud* exp = expBool();
	return new NoeudAffectation(var,exp);
}
////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::expBool(){
// <expBool> ::= <expBoolEt> { <opOu> <expBoolEt> }
    Noeud* expBET = expBoolEt();
    while (ls.getSymCour()=="ou") {
	Symbole operateur = opOu();
        Noeud* expBETDroit = expBoolEt();
        expBET = new NoeudOperateurBinaire(operateur,expBET,expBETDroit);
    }
    return expBET;
}
//////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::expBoolEt() {
// <expBoolEt> ::= <relation> { <opEt> <relation> }
    Noeud* relat = relation();
    while (ls.getSymCour()=="et") {
	Symbole operateur = opEt();
        Noeud* relatDroit = relation();
        relat = new NoeudOperateurBinaire(operateur,relat,relatDroit);
    }
    return relat;
}
////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::expression() {
// <expression> ::= <terme> { <opAdd> <terme> } | <chaine>
    Noeud* term = terme();
    if (ls.getSymCour()=="<CHAINE>")
    {
        ls.suivant(); ///////////////////////////
    }
    else
    {
        while (ls.getSymCour()=="+" || ls.getSymCour()=="-")
        {
            Symbole operateur = opAdd();
            Noeud* termDroit = terme();
            term = new NoeudOperateurBinaire(operateur,term,termDroit);
	}
    }
    return term;
}
////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::facteur() {
// <facteur> ::= <entier>  |  <variable>  |  - <facteur>  |  ( <expression> )
    Noeud* fact=NULL;
    if (ls.getSymCour()=="<VARIABLE>" || ls.getSymCour()=="<ENTIER>") {
        fact = ts.chercheAjoute(ls.getSymCour());
	ls.suivant();
    }
    else if (ls.getSymCour()=="-") {
	ls.suivant();
	// on représente le moins unaire (- facteur) par une soustractin binaire (0 - facteur)
	fact = new NoeudOperateurBinaire(Symbole("-"), ts.chercheAjoute(Symbole("0")), facteur());
    }
    else if (ls.getSymCour()=="(") {
        ls.suivant();
	fact=expression();
	sauterSymCour(")");
    }
    else 
        erreur("<facteur>");
    return fact;
}
////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::inst() {
// <affectation> | <instLire> | <instEcrire> | <instTq> | <instSi> | <instRepeter>
    Noeud* inst = NULL;
    if (ls.getSymCour()=="<VARIABLE>")
	inst = affectation();
    else if (ls.getSymCour()=="lire")
        inst = instLire();
//    else if (ls.getSymCour()=="ecrire")
//        inst = instEcrire();
    else if (ls.getSymCour()=="tantque")
        inst = instTq();
//    else if (ls.getSymCour()=="si")
//        inst = instSi();
    else if (ls.getSymCour()=="repeter")
        inst = instRepeter();
     else if (ls.getSymCour()=="pour")
        inst = instPour();
    else
        erreur("<inst>");
    return inst;        
}
////////////////////////////////////////////////////////////////////////////////
//void LecteurPhraseAvecArbre::instEcrire() {
// <instEcrire> ::= ecrire ( <chaine> )
//    sauterSymCour("ecrire");
//    sauterSymCour("(");
//    if (ls.getSymCour()=="<CHAINE>")
//    {
//        ts.chercheAjoute(ls.getSymCour());
//        ls.suivant();
//        sauterSymCour(")");
//    }
//    else
//    {
//        erreur("<CHAINE>");
//    }
//}
////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::instLire() {
////    <instLire> ::= lire ( <variable > )
    SymboleValue* variable=NULL;
  
    sauterSymCour("lire");
    sauterSymCour("(");
    if (ls.getSymCour()=="<VARIABLE>")
    {
        variable=ts.chercheAjoute(ls.getSymCour());
        
        ls.suivant();
        sauterSymCour(")");
        
    }
    else
    {
        erreur("<VARIABLE>");
    }
    return new NoeudInstLire(variable);
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::instPour() {
//      <pour>   ::= pour (<affectation>;<expBool>;<affectation>;) <seqInst> finpour
        sauterSymCour("pour");
        sauterSymCour("(");
        Noeud* aff=affectation();
        sauterSymCour(";");
        Noeud* expr=expBool();
        sauterSymCour(";");
        Noeud* aff2=affectation();
        sauterSymCour(";");
        sauterSymCour(")");
        Noeud* si=seqInst();
        sauterSymCour("finpour");
        NoeudInstPour* np = new NoeudInstPour(aff,expr,aff2,si);
        return np;
        
    }
////////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::instRepeter() {
////// <instRepeter> ::= repeter <seqInst> jusqua ( <expBool> )
    sauterSymCour("repeter");
    Noeud* si = seqInst();
    sauterSymCour("jusqua");
    sauterSymCour("(");
    Noeud* expr=expBool();
    sauterSymCour(")");
    NoeudInstRepeter* nr = new NoeudInstRepeter(expr,si);
    return nr;
}
////////////////////////////////////////////////////////////////////////////////////
//void LecteurPhraseAvecArbre::instSi() {
////// <instSi> ::= si ( <expBool> ) alors <seqInst1> { sinonsi ( <expBool> ) alors <sequInst2>} [ sinon <seqInst3> ] finsi
//    sauterSymCour("si");
//    sauterSymCour("(");
//    expBool();
//    sauterSymCour(")");
//    sauterSymCour("alors");
//    seqInst();
//    while (ls.getSymCour()=="sinonsi")
//    {
//        sauterSymCour("sinonsi");
//        sauterSymCour("(");
//        expBool();
//        sauterSymCour(")");
//        sauterSymCour("alors");
//        seqInst();
//    }
//    if (ls.getSymCour()=="sinon")
//    {
//        sauterSymCour("sinon");
//        seqInst();
//    }
//    sauterSymCour("finsi");
//}
////////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::instTq() {
//////// <instTq> ::= tantque ( <expBool> ) <seqInst> fintq
    sauterSymCour("tantque");
    sauterSymCour("(");
    Noeud* expr=expBool();
    sauterSymCour(")");
    sauterSymCour("faire");
    Noeud* si = seqInst();
    sauterSymCour("fintq");
    NoeudInstTq* ntq = new NoeudInstTq(expr,si);
    return ntq;
}
////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::programme() {
// <programme> ::= debut <seqInst> fin <EOF>
	sauterSymCour("debut");
	Noeud* si = seqInst();
	sauterSymCour("fin");
	testerSymCour("<FINDEFICHIER>");
	return si;
}
////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::relation(){
//// <relation> ::= <expression> { <opRel> <expression> }
    Noeud* expr = expression();
    while (ls.getSymCour()=="==" || ls.getSymCour()=="!=" || ls.getSymCour()=="<" || ls.getSymCour()=="<=" || ls.getSymCour()==">" || ls.getSymCour()==">=")
    {
        Symbole operateur = opRel();
        Noeud* exprDroit = expression();
        expr = new NoeudOperateurBinaire(operateur,expr,exprDroit);
    }
    return expr;
}
////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::seqInst() {
// <seqInst> ::= <inst> ; { <inst> ; }
    NoeudSeqInst* si = new NoeudSeqInst();
    do {
        si->ajouteInstruction(inst());
	sauterSymCour(";");
    } while (ls.getSymCour()=="<VARIABLE>" || ls.getSymCour()=="lire" || ls.getSymCour()=="ecrire" || ls.getSymCour()=="tantque" || ls.getSymCour()=="si" || ls.getSymCour()=="repeter"|| ls.getSymCour()=="pour");
	// tant que le symbole courant est un debut possible d'instruction...
    return si;
}
////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::terme() {
// <terme> ::= <facteur> { <opMult> <facteur> }
    Noeud* fact = facteur();
    while (ls.getSymCour()=="*" || ls.getSymCour()=="/") {
	Symbole operateur = opMult();
        Noeud* factDroit = facteur();
        fact = new NoeudOperateurBinaire(operateur,fact,factDroit);
    }
    return fact;
}